﻿/*global analogue*//*jslint bitwise: true, browser: true, eqeqeq: true, immed: true, newcap: true, nomen: true, onevar: true, plusplus: true, regexp: true, undef: true, white: true, indent: 4*/

analogue.events = (function (window) {
    var guid = 0, meta = null, root = document.documentElement;
    if (root.attachEvent) {
        meta = document.createElement('meta');
        meta.pseudoEvent = null;
        meta.attachEvent('onpropertychange', function (event) {
            if (event.propertyName === 'pseudoEvent') {            
                meta.pseudoEvent.listener.call(meta.pseudoEvent.target, meta.pseudoEvent.event);
                meta.returnValue = meta.pseudoEvent.event.returnValue;
                meta.cancelBubble = meta.pseudoEvent.event.cancelBubble;
            }
        });
        document.getElementsByTagName('head')[0].appendChild(meta);
    }
    return {
        add: (function () {
            if (root.addEventListener) {
                return function (type, listener) {
                    this.addEventListener(type, listener, false);
                    return this;
                };
            }
            return function (type, listener) {
                if (!listener.guid) {
                    listener.guid = guid += 1;
                }
                if (!this.queue) {
                    this.queue = {};
                }
                var listeners = this.queue[type];
                if (!listeners) {
                    listeners = this.queue[type] = {};
                    if (this['on' + type]) {
                        listeners[0] = this['on' + type];
                    }
                }
                listeners[listener.guid] = listener;
                this['on' + type] = analogue.events.handle;
                return this;
            };
        }()),
        fix: function (event) {
            event.pageX = event.clientX + (root.scrollLeft || document.body.scrollLeft || 0);
            event.pageY = event.clientY + (root.scrollTop || document.body.scrollTop || 0);
            event.preventDefault = function () {
                this.returnValue = false;
            };
            event.relatedTarget = event.fromElement === event.srcElement ? event.toElement : event.fromElement;
            event.stopPropagation = function () {
                this.cancelBubble = true;
            };
            event.target = event.target || event.srcElement;
            event.timeStamp = new Date().getTime();
            event.which = event.charCode = event.keyCode;
            if (!event.which && event.button) {
                event.which = (event.button === 1 ? 0 : (event.button === 4 ? 1 : (event.button === 2 ? 2 : 0)));
            }
            return event;
        },
        handle: function (event) {
            event = event || analogue.events.fix(window.event);
            var i, listeners = this.queue[event.type];
            for (i in listeners) {
                if (listeners.hasOwnProperty(i)) {
                    meta.pseudoEvent = {'listener': listeners[i], 'target': this, 'event': event};
                    if (meta.returnValue === false) {
                        event.preventDefault();
                    }
                    if (meta.cancelBubble === true) {
                        event.stopPropagation();
                    }
                }
            }
        },
        remove: (function () {
            if (root.removeEventListener) {
                return function (type, listener) {
                    this.removeEventListener(type, listener, false);
                    return this;
                };
            }
            return function (type, listener) {
                if (this.queue && this.queue[type] && listener.guid) {
                    delete this.queue[type][listener.guid];
                }
                return this;
            };
        }()),
        trigger: (function () {
            if (root.dispatchEvent) {
                return function (type, which) {
                    var event = null, charCode = 0, keyCode = 0;
                    if (/mouse|click/.test(type)) {
                        event = document.createEvent('MouseEvents');
                        if (event.initMouseEvent) {
                            event.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, which || 0, null);
                        } else {
                            event = document.createEvent('UIEvents');
                            event.initEvent(type, true, true);
                            event.button = which || 0;
                        }
                    } else if (/key(down|press|up)/.test(type)) {
                        if (which) {
                            which = typeof which === 'number' ? which : which.charCodeAt(0);
                            if (type === 'keypress') {
                                if ((which > 64 && which < 91) || (which > 96 && which < 123)) {
                                    charCode = which;
                                } else {
                                    keyCode = which;
                                }
                            } else {
                                keyCode = which;
                            }
                        }
                        try {
                            event = document.createEvent('KeyEvents');
                            event.initKeyEvent(type, true, true, window, false, false, false, false, keyCode, charCode);
                        } catch (e) {
                            try {
                                event = document.createEvent('Events');
                            } catch (er) {
                                event = document.createEvent('UIEvents');
                            } finally {
                                event.initEvent(type, true, true);
                                event.keyCode = keyCode;
                                event.charCode = charCode;
                                event.which = which || 0;
                            }
                        }
                    } else {
                        event = document.createEvent('HTMLEvents');
                        event.initEvent(type, true, true);
                    }
                    return this.dispatchEvent(event);
                };
            }
            if (root.fireEvent) {
                return function (type, which) {
                    var event = document.createEventObject();
                    if (/mouse|click/.test(type)) {
                        event.button = (which === 0 ? 1 : (which === 1 ? 4 : (which === 2 ? 2 : 0)));
                    } else if (/key(down|press|up)/.test(type)) {
                        event.keyCode = which ? (typeof which === 'number' ? which : which.charCodeAt(0)) : 0;
                    }
                    event.target = this;
                    event.type = type;
                    return this.fireEvent('on' + type, analogue.events.fix(event));
                };
            }
        }())
    };
}(this));